import java.util.*;
import java.io.*;
import org.apache.commons.lang3.StringUtils;

class CourseDatabase
{
	private ArrayList<Course> lstAllCourses;

	int nCourses;
	ReadStatus enReadStatus;
	ErrorStatus enErr;
	Table crseTable;
	int isCourseAdded;

	public static final String strDatabaseFileCourses  = new String(".\\CourseDataFile.csv");
	public static final String strDatabaseFileCoursesW  = strDatabaseFileCourses; //new String(".\\CourseDataFileVerify.csv");
	public static final String strDelim = new String(",");

	private boolean ReadCourseDatabase() {

		if (enReadStatus == ReadStatus.READ_COURSEDATA) {
			enErr = ErrorStatus.ERR_DB_ALREADY_READ;
			return false;
		}

		crseTable = new Table(strDatabaseFileCourses, strDelim);
		if (crseTable.IsErr()) {
			enErr = ErrorStatus.ERR_COURSE_DATABASE;
			return false;
		}

		int nCoursesInDb = crseTable.GetNumberOfLines();

		if (nCoursesInDb == 0) {
			enErr = ErrorStatus.ERR_COURSE_DATABASE_EMPTY;
			return false;
		}

		nCourses = 0;

		for (int n = 0; n < nCoursesInDb ; n++) {
			String strCrseMjr = new String(crseTable.ReadAt(n, CourseDatabaseIndices.enIndxCourseMajor.enVal()));
			String strCrseId = new String(crseTable.ReadAt(n, CourseDatabaseIndices.enIndxCourseId.enVal()));
			//System.out.println("Reading course: " + strCrseId);
			String strCrseName = new String(crseTable.ReadAt(n, CourseDatabaseIndices.enIndxCourseName.enVal()));
			String strCrseSumm = new String(crseTable.ReadAt(n, CourseDatabaseIndices.enIndxCourseSummary.enVal()));
			int nEnrolLimit = Integer.parseInt(crseTable.ReadAt(n, CourseDatabaseIndices.enIndxCourseEnrolLimit.enVal()));
			int nEnroll = Integer.parseInt(crseTable.ReadAt(n, CourseDatabaseIndices.enIndxCourseCurEnrolled.enVal()));
			String strLectAt = new String(crseTable.ReadAt(n, CourseDatabaseIndices.enIndxCourseLectureAt.enVal()));
			String strFrom = new String(crseTable.ReadAt(n, CourseDatabaseIndices.enIndxCourseDateFrom.enVal()));
			String strTo = new String(crseTable.ReadAt(n, CourseDatabaseIndices.enIndxCourseDateTo.enVal()));
			String strTchr = new String(crseTable.ReadAt(n, CourseDatabaseIndices.enIndxCourseTaughtBy.enVal()));

			//System.out.println("...Read course: " + strCrseId);

			Course crse = new Course(strCrseMjr, strCrseId, strCrseName, strCrseSumm, nEnrolLimit, nEnroll,
									strLectAt, strFrom, strTo, strTchr);

			lstAllCourses.add(crse);

			nCourses++; // needed when course is validated.
		}

		enReadStatus = ReadStatus.READ_COURSEDATA;

		return (nCourses > 0);
	}

	CourseDatabase() {
		nCourses = 0;
		enReadStatus = ReadStatus.READ_INIT;
		enErr = ErrorStatus.ERR_NOT_READY;
		lstAllCourses = new ArrayList<Course>();
		isCourseAdded = 0;

		this.ReadCourseDatabase();
	}

	public boolean isReady() {
		return (enReadStatus ==  ReadStatus.READ_COURSEDATA);
	}

	int numberOfCourses() {
		return nCourses;
	}

	public boolean addACourse(Course crseObj) {
		lstAllCourses.add(crseObj);

		String strCrseLine = crseObj.toString();
		crseTable.AddALine(strCrseLine);

		isCourseAdded++;
		return true;
	}

	public String[] getAllCourseIds() {
		String [] crseIds = new String [nCourses];

		if (nCourses > 0) {
			for (int n = 0; n < nCourses ; n++) {
				Course crse = lstAllCourses.get(n);
				crseIds[n] = crse.getCourseID();
			}
		}

		return crseIds;

	}
	public boolean AddStudent(String strCrseId) {
		Course crse = this.getCourseById(strCrseId);
		if (crse == null)
			return false;

		if (!crse.AddStudent())
			return false;

		int nCrseTableIndex = this.getCourseTableIndex(strCrseId);

		if (nCrseTableIndex == -1)
			return false;

		int nColIndx = CourseDatabaseIndices.enIndxCourseCurEnrolled.enVal();

		if (!crseTable.SetStringAt(nCrseTableIndex, nColIndx, Integer.toString(crse.getNCurrentEnrol())))
			return false;

		return UpdateDatabase();
	}

	public boolean DropStudent(String strCrseId) {
		Course crse = this.getCourseById(strCrseId);
		if (crse == null)
			return false;

		if (!crse.DropStudent())
			return false;

		int nCrseTableIndex = this.getCourseTableIndex(strCrseId);

		if (nCrseTableIndex == -1)
			return false;

		int nColIndx = CourseDatabaseIndices.enIndxCourseCurEnrolled.enVal();

		if (!crseTable.SetStringAt(nCrseTableIndex, nColIndx, Integer.toString(crse.getNCurrentEnrol())))
			return false;

		return UpdateDatabase();
	}

	public List<Course> getAllCourses() {
		return lstAllCourses;
	}

	public int getCourseTableIndex(String strCrseId) {
		int nSize = lstAllCourses.size();
		if (nSize == 0)
			return -1;

		for (int n = 0; n < nSize ; n++) {
			Course crs = lstAllCourses.get(n);
			String strId = crs.getCourseID();
			if (StringUtils.equals(strId, strCrseId)) {
				return n;
			}
		}

		return -1;
	}

	public Course getCourseById(String strCrseId) {
		int nSize = lstAllCourses.size();
		if (nSize == 0)
			return null;

		for (int n = 0; n < nSize ; n++) {
			Course crs = lstAllCourses.get(n);
			String strId = crs.getCourseID();
			if (StringUtils.equals(strId, strCrseId)) {
				return crs;
			}
		}

		return null;
	}

	ArrayList<Course> getAvailableCourses() {
		return lstAllCourses;
	}

	public boolean UpdateDatabase() {
		return crseTable.WriteToFile(strDatabaseFileCoursesW);
	}

	public boolean CloseDatabase() {
		if (isCourseAdded > 0) {
			if (crseTable.WriteToFile(strDatabaseFileCoursesW) == false)
				return false;
		}

		return true;
	}

}

